﻿using System;
using System.ComponentModel;
using System.Windows.Forms;
using AviationSimulator.DataItems.Mode.Send;
using AviationSimulator.Factories;
using AviationSimulator.Interfaces;
using AviationSimulator.Properties;
using Exchange;
using Nau.Parametrizer;

namespace AviationSimulator.GUI
{
    public delegate void CancelationPendingStatus(bool cancelationPending);

    public partial class MainForm : Form
    {
        private bool _parametersGridDoubleClicked;
        private ProgramMode _programMode;
        private WorkMode _workMode;
        private readonly SimulationRunner _runner;

        public CancelationPendingStatus CancelationCallback;
        public bool CancelationStatus;

        public MainForm()
        {
            _workMode = WorkMode.Idle;
            _runner = new SimulationRunner();

            InitializeComponent();
            DisplayParameters();
        }

        private void ImportFileRadioButton_CheckedChanged(object sender, EventArgs e)
        {
            if (!ImportFileRadioButton.Checked) return;

            ImportFilePanel.Visible = true;
            ParametersPanel.Visible = false;
            
            _programMode = ProgramMode.Import;
        }

        private void MathFunctionRadioButton_CheckedChanged(object sender, EventArgs e)
        {
            if (!MathFunctionRadioButton.Checked) return;

            ImportFilePanel.Visible = false;
            ParametersPanel.Visible = true;

            ParametersValueDataGrid.DataSource = ManagerFactory.MathFunctionMode.DataTable;
            ParametersValueDataGrid.EditMode = DataGridViewEditMode.EditProgrammatically;
            ParametersValueDataGrid.Update();

            _programMode = ProgramMode.MathFunction;
        }

        private void ManuallyRadioButton_CheckedChanged(object sender, EventArgs e)
        {
            if (!ManuallyRadioButton.Checked) return;

            ImportFilePanel.Visible = false;
            ParametersPanel.Visible = true;

            ParametersValueDataGrid.DataSource = ManagerFactory.ManualMode.DataTable;
            ParametersValueDataGrid.Update();
            ParametersValueDataGrid.EditMode = DataGridViewEditMode.EditOnF2;

            _programMode = ProgramMode.Manual;
        }

        private void PeriodicallyCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (PeriodicallyCheckBox.Checked)
            {
                label7.Enabled = true;
                PeriodTextBox.Enabled = true;
            }
            else
            {
                label7.Enabled = false;
                PeriodTextBox.Enabled = false;
            }
        }

        private void SendDestIpTextBoxTextChanged(object sender, EventArgs e)
        {
            if (SendDestIPTextBox.Text != "")
            {
                SendButton.Enabled = true;
                SendMenuItem.Enabled = true;
            }
            else
            {
                SendButton.Enabled = false;
                SendMenuItem.Enabled = false;
            }
        }

        private void ExitMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void OpenMenuItem_Click(object sender, EventArgs e)
        {
            IModeSerializable modeTodeserialize = null;

            var fileDialog = new OpenFileDialog();

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                switch (_programMode)
                {
                    case ProgramMode.Import:
                        modeTodeserialize = ManagerFactory.ImportMode;
                        break;
                    case ProgramMode.Manual:
                        modeTodeserialize = ManagerFactory.ManualMode;
                        break;
                    case ProgramMode.MathFunction:
                        modeTodeserialize = ManagerFactory.MathFunctionMode;
                        break;
                    case ProgramMode.Receive:
                        modeTodeserialize = ManagerFactory.ReceiveMode;
                        break;
                }

                if (modeTodeserialize != null)
                {
                    modeTodeserialize.Deserialize(fileDialog.FileName);
                    GetSendingParameters();
                    ParametersValueDataGrid.Update();
                }
            }
        }

        private void DisplayParameters()
        {
            ListOfParametersListBox.Items.Clear();

            //foreach (var parameter in ManagerFactory.ParametersManager.Parameters)
            //{
            //    ListOfParametersListBox.Items.Add(parameter);    
            //}
            var parameters = new Parameters();
            var serializer = new Serializer();

            parameters = serializer.DeSerializeObject(Application.StartupPath.Replace("\\Nau.Airplane.NetTester\\AviationSimulator\\AviationSimulator\\bin\\Debug", "") + "\\Parameters.prm");
            ListOfParametersListBoxDataBind(parameters.ParameterList);
        }

        private void ListOfParametersListBoxDataBind(System.Collections.Generic.List<Parameter> listOfParameter)
        {
            //Перевірка параметрів на пустоту
            if(listOfParameter != null)
                {
                    //Привязка даних з ParameterList до списку.
                     ListOfParametersListBox.DataSource = listOfParameter;
                     ListOfParametersListBox.DisplayMember = "Name";
                     ListOfParametersListBox.ValueMember = "Id";
                }

        }

        private void EnterParameterMathTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.Enter) return;

            AddParameterClicked();
        }

        private void AddParameterClicked()
        {
            ManagerFactory.ParametersManager.AddParameter(EnterParameterTextBox.Text);
            DisplayParameters();
            EnterParameterTextBox.Text = string.Empty;
        }

        private void DeleteFromParameterListButton_Click(object sender, EventArgs e)
        {
            try
            {
                var parameterName = ListOfParametersListBox.SelectedItem.ToString();
                ManagerFactory.ParametersManager.DeleteParameter(parameterName);
                DisplayParameters();
            }
            catch (NullReferenceException)
            {
            }
        }

        private void AddButton_Click(object sender, EventArgs e)
        {
            IModeDataTableParametrizable modeManager;
            
            if (MathFunctionRadioButton.Checked)
            {
                modeManager = ManagerFactory.MathFunctionMode;
            }
            else
            {
                modeManager = ManagerFactory.ManualMode;
            }

            try
            {
                var parameterName = ((Parameter)ListOfParametersListBox.SelectedItem).Name;

                modeManager.AddParameter(parameterName);
                ParametersValueDataGrid.Update();
            }
            catch (NullReferenceException)
            {
            }
        }

        private void RemoveButton_Click(object sender, EventArgs e)
        {
            IModeDataTableParametrizable modeManager;

            if (MathFunctionRadioButton.Checked)
            {
                modeManager = ManagerFactory.MathFunctionMode;
            }
            else
            {
                modeManager = ManagerFactory.ManualMode;
            }

            try
            {
                var parameterIndex = ParametersValueDataGrid.SelectedRows[0].Index;
                modeManager.RemoveParameter(parameterIndex);
                ParametersValueDataGrid.Update();
            }
            catch (ArgumentOutOfRangeException)
            {
            }
        }

        private void ParametersValueDataGrid_RowHeaderMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (!MathFunctionRadioButton.Checked) return;

            var parameterIndex = ParametersValueDataGrid.SelectedRows[0].Index;
            ManagerFactory.MathFunctionMode.EditParameterFunction(parameterIndex);
            ParametersValueDataGrid.Update();
        }

        private void BrowseButton_Click(object sender, EventArgs e)
        {
            var fileDialog = new OpenFileDialog();

            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                BrowsePathTextBox.Text = fileDialog.FileName;
                ManagerFactory.ImportMode.FilePath = fileDialog.FileName;
            }
        }

        private void SendButton_Click(object sender, EventArgs e)
        {
            SendClicked();
        }

        private void SendClicked()
        {
            if (_workMode == WorkMode.Idle && !SimulationBackgroundWorker.IsBusy)
            {
                SendModeBase currentMode = null; 

                switch (_programMode)
                {
                    case ProgramMode.Import:
                        ManagerFactory.ImportMode.FilePath = BrowsePathTextBox.Text;
                        currentMode = ManagerFactory.ImportMode;
                        break;
                    case ProgramMode.Manual:
                        currentMode = ManagerFactory.ManualMode;
                        break;
                    case ProgramMode.MathFunction:
                        currentMode = ManagerFactory.MathFunctionMode;
                        break;
                }

                if (currentMode != null)
                {
                    currentMode.Address = SendDestIPTextBox.Text;

                    if (!string.IsNullOrEmpty(SendDestPortTextBox.Text))
                        currentMode.Port = Convert.ToInt32(SendDestPortTextBox.Text);

                    currentMode.SendPeriodically = PeriodicallyCheckBox.Checked;

                    if (!string.IsNullOrEmpty(PeriodTextBox.Text))
                        currentMode.Period = Convert.ToInt32(PeriodTextBox.Text);
                }

                _workMode = WorkMode.Sending;
                CancelationCallback = new CancelationPendingStatus(_runner.SetCancelationStatus);
                SimulationBackgroundWorker.RunWorkerAsync();
            }
            else
            {
                SimulationBackgroundWorker.CancelAsync();
                CancelationStatus = true;
                CancelationCallback(SimulationBackgroundWorker.CancellationPending);
                _workMode = WorkMode.Idle;
            }

            SetWorkControlsStates();
        }

        private void ParametersValueDataGrid_RowLeave(object sender, DataGridViewCellEventArgs e)
        {
            if (!ManuallyRadioButton.Checked || !_parametersGridDoubleClicked) return;

            try
            {
                var parameterIndex = ParametersValueDataGrid.CurrentCell.RowIndex;
                var parameterValue = ParametersValueDataGrid.CurrentCell.EditedFormattedValue.ToString();

                ManagerFactory.ManualMode.EditParametervalue(parameterIndex, parameterValue);
                ParametersValueDataGrid.Update();
            }
            catch (FormatException)
            {
            }

            _parametersGridDoubleClicked = false;
        }

        private void ParametersValueDataGrid_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            _parametersGridDoubleClicked = true;
        }

        private void SaveMenuItem_Click(object sender, EventArgs e)
        {
            var fileDialog = new SaveFileDialog
                                 {
                                     Filter = Resources.FileTypesFilter
                                 };

            IModeSerializable modeToSerialize = null;

            if (fileDialog.ShowDialog() != DialogResult.OK) return;

            switch (_programMode)
            {
                case ProgramMode.Import:
                    ManagerFactory.ImportMode.FilePath = BrowsePathTextBox.Text;
                    modeToSerialize = ManagerFactory.ImportMode;
                    break;
                case ProgramMode.Manual:
                    modeToSerialize = ManagerFactory.ManualMode;
                    break;
                case ProgramMode.MathFunction:
                    modeToSerialize = ManagerFactory.MathFunctionMode;
                    break;
                case ProgramMode.Receive:
                    modeToSerialize = ManagerFactory.ReceiveMode;
                    break;
            }

            SetSendingParameters();

            if (modeToSerialize != null)
            {
                modeToSerialize.Serialize(fileDialog.FileName);
            }
        }

        private void SetSendingParameters()
        {
            SendModeBase modeToset = null;

            switch (_programMode)
            {
                case ProgramMode.Import:
                    modeToset = ManagerFactory.ImportMode;
                    break;
                case ProgramMode.Manual:
                    modeToset = ManagerFactory.ManualMode;
                    break;
                case ProgramMode.MathFunction:
                    modeToset = ManagerFactory.MathFunctionMode;
                    break;
                case ProgramMode.Receive:
                    ManagerFactory.ReceiveMode.Address = SenderAddressTextBox.Text;
                    ManagerFactory.ReceiveMode.Port = Convert.ToInt32(SenderPortTextBox.Text);
                    break;
            }

            if (modeToset == null) return;

            modeToset.Address = SendDestIPTextBox.Text;
            
            if (!string.IsNullOrEmpty(SendDestPortTextBox.Text))
                modeToset.Port = Convert.ToInt32(SendDestPortTextBox.Text);
            
            modeToset.SendPeriodically = PeriodicallyCheckBox.Checked;

            if (PeriodicallyCheckBox.Checked && !string.IsNullOrEmpty(PeriodTextBox.Text))
                modeToset.Period = Convert.ToInt32(PeriodTextBox.Text);
        }

        private void GetSendingParameters()
        {
            SendModeBase modeToGet = null;

            switch (_programMode)
            {
                case ProgramMode.Import:
                    modeToGet = ManagerFactory.ImportMode;
                    BrowsePathTextBox.Text = ManagerFactory.ImportMode.FilePath;
                    break;
                case ProgramMode.Manual:
                    modeToGet = ManagerFactory.ManualMode;
                    break;
                case ProgramMode.MathFunction:
                    modeToGet = ManagerFactory.MathFunctionMode;
                    break;
                case ProgramMode.Receive:
                    SenderAddressTextBox.Text = ManagerFactory.ReceiveMode.Address;

                    SenderPortTextBox.Text = ManagerFactory.ReceiveMode.Port != 0 ? 
                        ManagerFactory.ReceiveMode.Port.ToString() : string.Empty;

                    break;
            }

            if (modeToGet == null) return;

            SendDestIPTextBox.Text = modeToGet.Address;
            SendDestPortTextBox.Text = modeToGet.Port != 0 ? modeToGet.Port.ToString() : string.Empty;
            PeriodicallyCheckBox.Checked = modeToGet.SendPeriodically;

            if (PeriodicallyCheckBox.Checked)
                PeriodTextBox.Text = modeToGet.Period != 0 ? modeToGet.Period.ToString() : string.Empty;
        }

        private void SendReceiveTabs_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (SendReceiveTabs.SelectedTab == ReceiveTabPage)
            {
                _programMode = ProgramMode.Receive;

                SendMenuItem.Enabled = false;
                StartReceivingMenuItem.Enabled = true;
            }
            else
            {
                if (ImportFileRadioButton.Checked)
                    _programMode = ProgramMode.Import;

                if (MathFunctionRadioButton.Checked)
                    _programMode = ProgramMode.MathFunction;

                if (ManuallyRadioButton.Checked)
                    _programMode = ProgramMode.Manual;

                SendMenuItem.Enabled = true;
                StartReceivingMenuItem.Enabled = false;
            }
        }

        private void SetWorkControlsStates()
        {
            switch (_workMode)
            {
                case WorkMode.Idle:
                    // Send controls
                    EnableIdleWorkMode();

                    break;
                
                case WorkMode.Sending:
                    EnableSendWorkMode();

                    break;

                case WorkMode.Receiving:
                    SendTabPage.Enabled = false;
                    
                    // Menu items
                    SendMenuItem.Enabled = false;
                    ClearMenuItem.Enabled = false;
                    OpenMenuItem.Enabled = false;

                    // Receive controls
                    StartReceivingMenuItem.Text = Resources.Stop;
                    StartReceiveButton.Text = Resources.Stop;
                    SenderAddressTextBox.Enabled = false;
                    SenderPortTextBox.Enabled = false;

                    break;
            }
        }

        private void EnableSendWorkMode()
        {
            // Send controls
            SendButton.Enabled = true;
            SendMenuItem.Enabled = true;
            SendButton.Text = Resources.Stop;
            SendMenuItem.Text = Resources.Stop;
            SendDestIPTextBox.Enabled = false;
            SendDestPortTextBox.Enabled = false;
            PeriodicallyCheckBox.Enabled = false;
            PeriodTextBox.Enabled = false;

            switch (_programMode)
            {
                case ProgramMode.Import:
                    MathFunctionRadioButton.Enabled = false;
                    ManuallyRadioButton.Enabled = false;
                    BrowsePathTextBox.Enabled = false;
                    BrowseButton.Enabled = false;
                    break;

                case ProgramMode.Manual:
                    ImportFileRadioButton.Enabled = false;
                    MathFunctionRadioButton.Enabled = false;
                    AddButton.Enabled = false;
                    RemoveButton.Enabled = false;
                    ParametersValueDataGrid.Enabled = false;
                    DeleteFromParameterListButton.Enabled = false;
                    break;

                case ProgramMode.MathFunction:
                    ImportFileRadioButton.Enabled = false;
                    ManuallyRadioButton.Enabled = false;
                    AddButton.Enabled = false;
                    RemoveButton.Enabled = false;
                    ParametersValueDataGrid.Enabled = false;
                    DeleteFromParameterListButton.Enabled = false;
                    break;
            }

            // Menu item controls
            ReceiveTabPage.Enabled = false;
            StartReceivingMenuItem.Enabled = false;
            ClearMenuItem.Enabled = false;
            OpenMenuItem.Enabled = false;
        }

        private void EnableIdleWorkMode()
        {
            // Send option controls
            SendButton.Enabled = true;

            if (SendReceiveTabs.SelectedTab == SendTabPage)
                SendMenuItem.Enabled = true;
            
            SendDestIPTextBox.Enabled = true;
            SendDestPortTextBox.Enabled = true;
            PeriodicallyCheckBox.Enabled = true;

            if (PeriodicallyCheckBox.Checked)
                PeriodTextBox.Enabled = true;

            // Menu controls
            SendButton.Text = Resources.Start;
            SendMenuItem.Text = Resources.Start;
                    
            // Send radiobuttons
            ImportFileRadioButton.Enabled = true;
            MathFunctionRadioButton.Enabled = true;
            ManuallyRadioButton.Enabled = true;

            // Import controls
            BrowsePathTextBox.Enabled = true;
            BrowseButton.Enabled = true;

            // Math function and manual controls
            AddButton.Enabled = true;
            RemoveButton.Enabled = true;
            ParametersValueDataGrid.Enabled = true;
            DeleteFromParameterListButton.Enabled = true;

            // Receive controls
            SenderAddressTextBox.Enabled = true;
            SenderPortTextBox.Enabled = true;
            StartReceiveButton.Text = Resources.Receive;


            // Tabs
            ReceiveTabPage.Enabled = true;
            SendTabPage.Enabled = true;

            // Menu item controls
            ClearMenuItem.Enabled = true;
            OpenMenuItem.Enabled = true;

            if (SendReceiveTabs.SelectedTab == ReceiveTabPage)
                StartReceivingMenuItem.Enabled = true;
            
            StartReceivingMenuItem.Text = Resources.Receive;
        }

        private void SendMenuItem_Click(object sender, EventArgs e)
        {
            SendClicked();
        }

        private void StartReceiveButton_Click(object sender, EventArgs e)
        {
            ReceiveClicked();
        }

        private void ReceiveClicked()
        {
            if (_workMode == WorkMode.Idle && !SimulationBackgroundWorker.IsBusy)
            {
                ManagerFactory.PackageManager.ClearTempPackagesStorage();
                
                ManagerFactory.ReceiveMode.Address = SenderAddressTextBox.Text;

                if (!string.IsNullOrEmpty(SenderPortTextBox.Text))
                    ManagerFactory.ReceiveMode.Port = Convert.ToInt32(SenderPortTextBox.Text);

                _workMode = WorkMode.Receiving;
                CancelationCallback = new CancelationPendingStatus(_runner.SetCancelationStatus);
                SimulationBackgroundWorker.RunWorkerAsync();
            }
            else
            {
                SimulationBackgroundWorker.CancelAsync();
                CancelationStatus = true;
                CancelationCallback(SimulationBackgroundWorker.CancellationPending);
                _workMode = WorkMode.Idle;

                ManagerFactory.ReceiveMode.LoadPackagesFromTemp();
                ReceivedPackagesDataGrid.DataSource = ManagerFactory.ReceiveMode.ReceivedPackagesDataTable;
                ReceivedPackagesDataGrid.Update();

                if (ManagerFactory.PackageManager.TemporaryPackageStorage.Count > 0)
                    SavePackagesButton.Enabled = true;
            }

            SetWorkControlsStates();
        }

        private void StartReceivingMenuItem_Click(object sender, EventArgs e)
        {
            ReceiveClicked();
        }

        private void SimulationBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var worker = sender as BackgroundWorker;
            _runner.CancelationPendingStatus = SimulationBackgroundWorker.CancellationPending;

            if (worker != null)
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                }
                else
                {
                    _runner.Start(_programMode);
                }
        }

        private void ReceivedPackagesDataGrid_SelectionChanged(object sender, EventArgs e)
        {
            try
            {
                var packageIndex = ReceivedPackagesDataGrid.SelectedRows[0].Index;
                ManagerFactory.ReceiveMode.UploadPackageParameters(packageIndex);
                PackageDetailsDataGrid.DataSource = ManagerFactory.ReceiveMode.PackageDetailsDataTable;
                PackageDetailsDataGrid.Update();
            }
            catch (ArgumentOutOfRangeException)
            {
            }
        }

        private void ClearMenuItem_Click(object sender, EventArgs e)
        {
            if (SendReceiveTabs.SelectedTab == SendTabPage)
            {
                SendModeBase currentMode = null;

                switch (_programMode)
                {
                    case ProgramMode.Import:
                        BrowsePathTextBox.Text = string.Empty;
                        ManagerFactory.ImportMode.FilePath = string.Empty;
                        break;
                    case ProgramMode.Manual:
                        ManagerFactory.ManualMode.Package.Parameters.Clear();
                        ManagerFactory.ManualMode.DataTable.Clear();
                        ParametersValueDataGrid.Update();
                        break;
                    case ProgramMode.MathFunction:
                        ManagerFactory.MathFunctionMode.ParameterFunctions.Clear();
                        ManagerFactory.MathFunctionMode.DataTable.Clear();
                        ParametersValueDataGrid.Update();
                        break;
                }
            }
            else
            {
                ManagerFactory.ReceiveMode.ReceivedPackagesDataTable.Clear();
                ManagerFactory.PackageManager.TemporaryPackageStorage.Clear();
                ManagerFactory.ReceiveMode.PackageDetailsDataTable.Clear();
                
                PackageDetailsDataGrid.Update();
                ReceivedPackagesDataGrid.ClearSelection();
                ReceivedPackagesDataGrid.Update();
            }
        }

        private void AddParameter_Click(object sender, EventArgs e)
        {
            AddParameterClicked();
        }

        private void SavePackagesButton_Click(object sender, EventArgs e)
        {
            var saveDialog = new SaveFileDialog { Filter = Resources.SavePackageTypeFilters };

            if (saveDialog.ShowDialog() == DialogResult.OK)
            {
                ManagerFactory.PackageManager.SavePackagesFromTemp(saveDialog.FileName);
                SavePackagesButton.Enabled = false;
            }
        }
    }
}
